package org.xtense.model.actions;

import org.dom4j.Attribute;
import org.dom4j.CDATA;
import org.dom4j.Comment;
import org.dom4j.Document;
import org.dom4j.DocumentType;
import org.dom4j.Element;
import org.dom4j.Entity;
import org.dom4j.Namespace;
import org.dom4j.ProcessingInstruction;
import org.dom4j.Text;
import org.dom4j.Visitor;
import org.xtense.engine.actions.UpdateAction;
import org.xtense.util.StringUtil;

public class AddVisitor implements Visitor {
	private int documentID, elementPre, parentPre;
	private String contextPath;
	private ElementInterceptor eleInter;
	private AttributeInterceptor attInter;
	private int preIndex;

	public AddVisitor(ElementInterceptor eleInter,
			AttributeInterceptor attInter, int documentID,
			int elementPre, int parentPre, String pathValue) {
		this.eleInter = eleInter;
		this.attInter = attInter;
		this.documentID = documentID;
		this.elementPre = elementPre;
		this.parentPre = parentPre;
		this.contextPath = pathValue;
		preIndex = 1;
	}
	
	private String getPath(String basepath, Element user, boolean isChild) {
		if (isChild) {
			return StringUtil.append(new Object[] { basepath, "/",
					user.getName(), "#" });
		} else {
			String base = basepath.substring(0, basepath.lastIndexOf('/') + 1);
			return StringUtil
					.append(new Object[] { base, user.getName(), "#" });
		}
	}
	
	@Override
	public void visit(Element node) {

		if (preIndex == 1) {
			Element added = (Element) UpdateAction.getInstance(documentID)
					.getCache().getNode(node);
			if (added.getParent().elements().indexOf(added) == 0) {
				String path = getPath(contextPath, node, true);
				UpdateAction.getInstance(documentID).getCache().cacheSql(
						UpdateHelper.getInstance()
						.addElementAfter(documentID, elementPre, parentPre,
								node.getName(), path, true));
				UpdateAction.getInstance(documentID).getCache().cachePre(added,
						elementPre + preIndex,
						elementPre);
				UpdateAction.getInstance(documentID).getCache().cachePath(
						added, path);
			} else {
				String path = getPath(contextPath, node, false);
				UpdateAction.getInstance(documentID).getCache().cacheSql(
						UpdateHelper.getInstance()
						.addElementAfter(documentID, elementPre, parentPre,
								node.getName(), path, false));
				UpdateAction.getInstance(documentID).getCache().cachePre(added,
						elementPre + 1,
						parentPre);
				UpdateAction.getInstance(documentID).getCache().cachePath(
						added, path);
			}
			
			// add text
			if (node.getTextTrim().length() > 0) {
				int elePre = UpdateAction.getInstance(documentID).getCache()
						.getPre(added)[0];
				UpdateAction.getInstance(documentID).getCache().cacheSql(
						UpdateHelper.getInstance().addText(
						documentID, elePre, node.getTextTrim()));				
			}
			preIndex++;
		} else {
			Element toAdd = eleInter.createElement(node.getName());
			UpdateAction.getInstance(documentID).getCache().cacheNode(node,
					toAdd);
			
			if (node.getParent().elements().indexOf(node) == 0) {
				Element base = (Element) UpdateAction.getInstance(documentID)
						.getCache().getNode(node.getParent());
				
				base.add(toAdd);
				
				int[] pre = UpdateAction.getInstance(documentID).getCache()
						.getPre(base);
				String path = getPath(UpdateAction.getInstance(documentID)
						.getCache().getPath(base), node, true);
				
				UpdateAction.getInstance(documentID).getCache().cacheSql(
						UpdateHelper.getInstance()
						.addElementAfter(documentID, pre[0], pre[1],
								node.getName(), path, true));
				
				UpdateAction.getInstance(documentID).getCache().cachePre(toAdd,
						pre[0] + 1, pre[0]);
				UpdateAction.getInstance(documentID).getCache().cachePath(
						toAdd, path);				
				
			} else {
				int index = node.getParent().elements().indexOf(node);

				Element base = (Element) UpdateAction.getInstance(documentID)
						.getCache().getNode(
								(Element) node
						.getParent()
						.elements().get(index - 1));
				
				base.add(toAdd);
				
				int[] pre = UpdateAction.getInstance(documentID).getCache()
						.getPre(base);
				String path = getPath(UpdateAction.getInstance(documentID)
						.getCache().getPath(base), node, false);
				
				UpdateAction.getInstance(documentID).getCache().cacheSql(
						UpdateHelper.getInstance()
						.addElementAfter(documentID, pre[0], pre[1],
								node.getName(), path, false));

				UpdateAction.getInstance(documentID).getCache().cachePre(toAdd,
						pre[0] + 1, pre[1]);
				UpdateAction.getInstance(documentID).getCache().cachePath(
						toAdd, path);

			}
			
			// add text
			if (node.getTextTrim().length() > 0) {
				int elePre = UpdateAction.getInstance(documentID).getCache()
						.getPre(toAdd)[0];
				UpdateAction.getInstance(documentID).getCache().cacheSql(
						UpdateHelper.getInstance().addText(
						documentID, elePre, node.getTextTrim()));
			}
			
			preIndex++;
		}

	}

	@Override
	public void visit(Attribute node) {
		Attribute att = attInter.createAttribute(node.getName(), node
				.getValue());
		Element base = (Element) UpdateAction.getInstance(documentID)
				.getCache().getNode(node.getParent());
		
		base.add(att);
		
		int elePre = UpdateAction.getInstance(documentID).getCache().getPre(
				base)[0];
		
		UpdateAction.getInstance(documentID).getCache().cacheSql(
				UpdateHelper.getInstance().addAttribute(
				documentID, elePre, node.getName(), node.getValue()));

	}

	@Override
	public void visit(Document document) {

	}

	@Override
	public void visit(DocumentType documentType) {

	}

	@Override
	public void visit(CDATA node) {

	}

	@Override
	public void visit(Comment node) {

	}

	@Override
	public void visit(Entity node) {

	}

	@Override
	public void visit(Namespace namespace) {

	}

	@Override
	public void visit(ProcessingInstruction node) {

	}

	@Override
	public void visit(Text node) {

	}

}
